package rexsee.core.application;

import java.io.File;
import java.util.Locale;

import rexsee.core.browser.Browser;
import rexsee.core.browser.RexseeUrl;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.lang.RexseeLanguage;
import rexsee.core.utilities.Utilities;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Html;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.widget.Toast;

public class RexseeApplication implements JavascriptInterface {

	public static final String INTERFACE_NAME = "Application";
	@Override
	public String getInterfaceName() {
		return resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return childBrowser.application;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeApplication(childBrowser.getContext());
	}

	public static final String EXCEPTION_PREFIX = "[Exception]";

	public static final String DATABASE_APPLICATION = "application.db";
	public static final String TABLE_RUNTIMES = "runtimes";
	public static final String TABLE_TIMEOUT = "timeout";
	public static final String TABLE_ENCODING = "encoding";
	public static final String TABLE_USER_AGENT = "userAgent";
	public static final String TABLE_CACHE = "cache";
	public static final String TABLE_HOME = "homepage";

	private static final int MIN_TIMEOUT = 5;
	private static final int MAX_TIMEOUT = 120;
	private static final int DEFAULT_TIMEOUT = 30;
	private static final String DEFAULT_ENCODING = "utf-8";

	public final Drawable icon;
	public final String label;
	public final Resource resources;

	public final float screenDensity;
	public final int screenWidth;
	public final int screenHeight;

	public final String language;
	public final String country;

	private final Context mContext;

	public RexseeApplication(Context context) {

		super();
		mContext = context;
		resources = new Resource(mContext);

		ApplicationInfo appInfo;
		try {
			appInfo = mContext.getPackageManager().getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA);
		} catch (NameNotFoundException e) {
			appInfo = null;
		}
		PackageManager packageManager = mContext.getPackageManager();
		icon = (appInfo == null) ? new ColorDrawable(Color.BLACK) : packageManager.getApplicationIcon(appInfo);
		label = (appInfo == null) ? resources.prefix : (String) packageManager.getApplicationLabel(appInfo);

		Resources r = mContext.getResources();
		Locale locale = r.getConfiguration().locale;

		language = locale.getLanguage();
		country = locale.getCountry();

		DisplayMetrics displayMetrics = r.getDisplayMetrics();
		screenDensity = displayMetrics.density;
		screenWidth = displayMetrics.widthPixels;
		screenHeight = displayMetrics.heightPixels;

		addRunTimes();
	}

	public static void setUserAgent(Context context, String agent) {
		try {
			SQLiteDatabase db = context.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
			db.execSQL("CREATE TABLE if not exists " + TABLE_USER_AGENT + " (agent TEXT);");
			db.execSQL("DELETE FROM " + TABLE_USER_AGENT + ";");
			db.execSQL("INSERT INTO " + TABLE_USER_AGENT + " VALUES ('" + agent + "');");
			db.close();
		} catch (Exception e) {
		}
	}
	public static String getUserAgent(Context context) {
		try {
			SQLiteDatabase db = context.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
			db.execSQL("CREATE TABLE if not exists " + TABLE_USER_AGENT + " (agent TEXT);");
			Cursor cursor = db.rawQuery("SELECT * from " + TABLE_USER_AGENT + ";", null);
			if (cursor == null || cursor.getCount() == 0) {
				return "";
			} else {
				cursor.moveToFirst();
				String rtn = cursor.getString(0);
				cursor.close();
				return rtn;
			}
		} catch (Exception e) {
			return "";
		}
	}
	public static String getDefaultEncoding(Context context) {
		SQLiteDatabase db = null;
		try {
			db = context.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
		} catch (Exception e) {
		}
		if (db == null) return DEFAULT_ENCODING;
		try {
			db.execSQL("CREATE TABLE if not exists " + TABLE_ENCODING + " (encoding TEXT);");
			Cursor cursor = db.rawQuery("SELECT * from " + TABLE_ENCODING + ";", null);
			if (cursor == null || cursor.getCount() == 0) {
				try {
					cursor.close();
				} catch (Exception e) {
				}
				db.close();
				return DEFAULT_ENCODING;
			} else {
				cursor.moveToFirst();
				String rtn = cursor.getString(0);
				cursor.close();
				db.close();
				return rtn;
			}
		} catch (Exception e) {
			db.close();
			return DEFAULT_ENCODING;
		}
	}

	public void confirm(String title, String message, Runnable runnable) {
		Resources r = ((Activity) mContext).getResources();
		confirm(title, message, r.getString(android.R.string.ok), r.getString(android.R.string.cancel), runnable, null);
	}
	public void confirm(final String title, final String message, final String confirmText, final String cancelText, final Runnable confirmRunnable, final Runnable cancelRunnable) {
		((Activity) mContext).runOnUiThread(new Runnable() {
			@Override
			public void run() {
				AlertDialog dialog = new AlertDialog.Builder(mContext).create();
				dialog.setIcon(icon);
				dialog.setTitle(title);
				dialog.setMessage(message);
				dialog.setOnKeyListener(new Dialog.OnKeyListener() {
					@Override
					public boolean onKey(DialogInterface arg0, int arg1, KeyEvent arg2) {
						if (arg1 == KeyEvent.KEYCODE_SEARCH) return true;
						else return false;
					}
				});
				if (confirmText != null) {
					dialog.setButton(DialogInterface.BUTTON_NEGATIVE, confirmText, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int whichButton) {
							dialog.dismiss();
							if (confirmRunnable != null) confirmRunnable.run();
						}
					});
				}
				if (cancelText != null) {
					dialog.setButton(DialogInterface.BUTTON_POSITIVE, cancelText, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int whichButton) {
							dialog.dismiss();
							if (cancelRunnable != null) cancelRunnable.run();
						}
					});
				}
				dialog.show();
			}
		});
	}
	public void alert(String message) {
		alert(RexseeLanguage.TITLE_ALERT, message);
	}
	public void error(String message) {
		alert(RexseeLanguage.TITLE_ERROR, message);
	}
	public void alert(final String title, final String message) {
		((Activity) mContext).runOnUiThread(new Runnable() {
			@Override
			public void run() {
				AlertDialog dialog = new AlertDialog.Builder(mContext).create();
				dialog.setIcon(icon);
				dialog.setTitle(title);
				dialog.setMessage(Html.fromHtml(message));
				dialog.setButton(DialogInterface.BUTTON_POSITIVE, ((Activity) mContext).getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int whichButton) {
						dialog.dismiss();
						//syncAlertTag = true;
					}
				});
				dialog.show();
			}
		});
	}

	public void toast(final int message) {
		((Activity) mContext).runOnUiThread(new Runnable() {
			@Override
			public void run() {
				Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
			}
		});
	}
	public void toast(final String message) {
		((Activity) mContext).runOnUiThread(new Runnable() {
			@Override
			public void run() {
				Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
			}
		});
	}

	//JavaScript Interface
	public void exit() {
		System.exit(2);
	}
	public void confirmExit() {
		confirm(RexseeLanguage.TITLE_CONFIRM, RexseeLanguage.CONFIRM_QUIT, new Runnable() {
			@Override
			public void run() {
				exit();
			}
		});
	}
	public void quit() {
		((Activity) mContext).finish();
	}
	public void confirmQuit() {
		confirm(RexseeLanguage.TITLE_CONFIRM, RexseeLanguage.CONFIRM_QUIT, new Runnable() {
			@Override
			public void run() {
				quit();
			}
		});
	}
	public void restart() {
		PendingIntent pendingIntent = PendingIntent.getActivity(((Activity) mContext).getBaseContext(), 0, new Intent(((Activity) mContext).getIntent()), ((Activity) mContext).getIntent().getFlags());
		AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
		mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pendingIntent);
		System.exit(2);
	}
	public void confirmRestart() {
		confirm(RexseeLanguage.TITLE_CONFIRM, RexseeLanguage.CONFIRM_RESTART, new Runnable() {
			@Override
			public void run() {
				restart();
			}
		});
	}
	public void uninstall() {
		Intent delete = new Intent(Intent.ACTION_DELETE, Uri.parse("package:" + mContext.getPackageName()));
		mContext.startActivity(delete);
	}
	public void confirmUninstall() {
		confirm(RexseeLanguage.TITLE_CONFIRM, RexseeLanguage.CONFIRM_UNINSTALL, new Runnable() {
			@Override
			public void run() {
				uninstall();
			}
		});
	}

	public void askForExitOrRestart(final String title, final String message) {
		confirm(title, message, RexseeLanguage.ACTION_QUIT, RexseeLanguage.ACTION_RESTART, new Runnable() {
			@Override
			public void run() {
				exit();
			}
		}, new Runnable() {
			@Override
			public void run() {
				restart();
			}
		});
	}
	public void askForExit(final String title, final String message) {
		confirm(title, message, RexseeLanguage.ACTION_QUIT, null, new Runnable() {
			@Override
			public void run() {
				exit();
			}
		}, null);
	}

	public String getName() {
		return mContext.getPackageName();
	}
	public String getLabel() {
		return label;
	}
	public int getVersionCode() {
		try {
			return (mContext.getPackageManager()).getPackageInfo(mContext.getPackageName(), 0).versionCode;
		} catch (Exception e) {
			return 0;
		}
	}
	public String getVersionName() {
		try {
			return (mContext.getPackageManager()).getPackageInfo(mContext.getPackageName(), 0).versionName;
		} catch (Exception e) {
			return "";
		}
	}
	public String getEditionName() {
		return mContext.getClass().getSimpleName().replace("Rexsee", "").replace("Activity", "").toLowerCase();
	}

	public int getInstalledTime() {
		ApplicationInfo appInfo;
		try {
			appInfo = mContext.getPackageManager().getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA);
		} catch (NameNotFoundException e) {
			appInfo = null;
		}
		return (appInfo == null) ? -1 : (int) (System.currentTimeMillis() - (new File(appInfo.sourceDir)).lastModified()) / 1000;
	}

	public void addRunTimes() {
		SQLiteDatabase db = null;
		try {
			db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
		} catch (Exception e) {
		}
		if (db == null) return;
		try {
			db.execSQL("CREATE TABLE if not exists " + TABLE_RUNTIMES + " (times int);");
			Cursor cursor = db.rawQuery("SELECT * from " + TABLE_RUNTIMES + ";", null);
			int current;
			if (cursor == null || cursor.getCount() == 0) {
				current = 0;
			} else {
				cursor.moveToFirst();
				current = cursor.getInt(0);
			}
			current = current + 1;
			db.execSQL("DELETE FROM " + TABLE_RUNTIMES + ";");
			db.execSQL("INSERT INTO " + TABLE_RUNTIMES + " VALUES (" + current + ");");
			cursor.close();
		} catch (Exception e) {
		}
		db.close();
	}
	public int getRunTimes() {
		SQLiteDatabase db = null;
		try {
			db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
		} catch (Exception e) {
		}
		if (db == null) return 0;
		try {
			db.execSQL("CREATE TABLE if not exists " + TABLE_RUNTIMES + " (times int);");
			Cursor cursor = db.rawQuery("SELECT * from " + TABLE_RUNTIMES + ";", null);
			if (cursor == null || cursor.getCount() == 0) {
				try {
					cursor.close();
				} catch (Exception e) {
				}
				db.close();
				return 0;
			} else {
				cursor.moveToFirst();
				int rtn = cursor.getInt(0);
				cursor.close();
				db.close();
				return rtn;
			}
		} catch (Exception e) {
			db.close();
			return 0;
		}
	}

	public String getHome() {
		return resources.home;
	}
	public String getAuthorName() {
		return resources.author;
	}
	public String getAuthorEmail() {
		return resources.email;
	}
	public String getDomailWhiteList() {
		if (resources.domainWhiteList == null) return "";
		String rtn = "";
		for (int i = 0; i < resources.domainWhiteList.length; i++) {
			rtn += (i == 0) ? "\"" + resources.domainWhiteList[i] + "\"" : ",\"" + resources.domainWhiteList[i] + "\"";
		}
		return "[" + rtn + "]";
	}

	public void setDeveloperHome(String homePage) {
		homePage = RexseeUrl.cleanUrl_(homePage);
		Uri uri = Uri.parse(homePage);
		String scheme = uri.getScheme();
		if (!scheme.equals("http") && !scheme.equals("https") && !scheme.equals("file")) {
			Toast.makeText(mContext, "Invalid Scheme: " + scheme, Toast.LENGTH_LONG);
			return;
		}
		SQLiteDatabase db = null;
		try {
			db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
		} catch (Exception e) {
		}
		if (db == null) return;
		try {
			db.execSQL("CREATE TABLE if not exists " + TABLE_HOME + " (url TEXT);");
			db.execSQL("DELETE FROM " + TABLE_HOME + ";");
			if (homePage != null) {
				db.execSQL("INSERT INTO " + TABLE_HOME + " VALUES ('" + homePage + "');");
			}
		} catch (Exception e) {
		}
		db.close();
	}
	public String getDeveloperHome() {
		SQLiteDatabase db = null;
		try {
			db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
		} catch (Exception e) {
		}
		if (db == null) return resources.prefix + ":home_setup";
		try {
			db.execSQL("CREATE TABLE if not exists " + TABLE_HOME + " (url TEXT);");
			Cursor cursor = db.rawQuery("SELECT * from " + TABLE_HOME + ";", null);
			if (cursor == null || cursor.getCount() == 0) {
				try {
					cursor.close();
				} catch (Exception e) {
				}
				db.close();
				return resources.prefix + ":home_setup";
			} else {
				cursor.moveToFirst();
				String rtn = cursor.getString(0);
				cursor.close();
				db.close();
				return rtn;
			}
		} catch (Exception e) {
			db.close();
			return resources.prefix + ":home_setup";
		}
	}

	public String getCurrentHome() {
		String developerHome = getDeveloperHome();
		if (resources.home != null && !resources.home.equals("")) {
			if (developerHome.startsWith("file://")) return developerHome;
			else return resources.home;
		} else {
			return developerHome;
		}
	}

	public void setTimeout() {
		setTimeout(DEFAULT_TIMEOUT);
	}
	public void setTimeout(int seconds) {
		if (seconds > MAX_TIMEOUT || seconds < MIN_TIMEOUT) {
			Toast.makeText(mContext, "Invalid arguments. The timout should be between " + MIN_TIMEOUT + " seconds and " + MAX_TIMEOUT + " seconds.", Toast.LENGTH_LONG).show();
		} else {
			try {
				SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
				db.execSQL("CREATE TABLE if not exists " + TABLE_TIMEOUT + " (seconds int);");
				db.execSQL("DELETE FROM " + TABLE_TIMEOUT + ";");
				db.execSQL("INSERT INTO " + TABLE_TIMEOUT + " VALUES (" + seconds + ");");
				db.close();
			} catch (Exception e) {
			}
		}
	}
	public int getTimeout() {
		SQLiteDatabase db = null;
		try {
			db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
		} catch (Exception e) {
		}
		if (db == null) return DEFAULT_TIMEOUT;
		try {
			db.execSQL("CREATE TABLE if not exists " + TABLE_TIMEOUT + " (seconds int);");
			Cursor cursor = db.rawQuery("SELECT * from " + TABLE_TIMEOUT + ";", null);
			if (cursor == null || cursor.getCount() == 0) {
				try {
					cursor.close();
				} catch (Exception e) {
				}
				db.close();
				return DEFAULT_TIMEOUT;
			} else {
				cursor.moveToFirst();
				int rtn = cursor.getInt(0);
				cursor.close();
				db.close();
				return rtn;
			}
		} catch (Exception e) {
			db.close();
			return DEFAULT_TIMEOUT;
		}
	}

	public void setDefaultEncoding(String encoding) {
		try {
			SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
			db.execSQL("CREATE TABLE if not exists " + TABLE_ENCODING + " (encoding TEXT);");
			db.execSQL("DELETE FROM " + TABLE_ENCODING + ";");
			db.execSQL("INSERT INTO " + TABLE_ENCODING + " VALUES ('" + encoding + "');");
			db.close();
		} catch (Exception e) {
		}
	}
	public String getDefaultEncoding() {
		return getDefaultEncoding(mContext);
	}

	public void setAutoClearCache(boolean autoClear) {
		try {
			SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
			db.execSQL("CREATE TABLE if not exists " + TABLE_CACHE + " (autoclear int);");
			db.execSQL("DELETE FROM " + TABLE_CACHE + ";");
			db.execSQL("INSERT INTO " + TABLE_CACHE + " VALUES (" + ((autoClear) ? 1 : 0) + ");");
			db.close();
		} catch (Exception e) {
		}
	}
	public boolean getAutoClearCache() {
		SQLiteDatabase db = null;
		try {
			db = mContext.openOrCreateDatabase(DATABASE_APPLICATION, Context.MODE_PRIVATE, null);
		} catch (Exception e) {
		}
		if (db == null) return true;
		try {
			db.execSQL("CREATE TABLE if not exists " + TABLE_CACHE + " (autoclear int);");
			Cursor cursor = db.rawQuery("SELECT * from " + TABLE_CACHE + ";", null);
			if (cursor == null || cursor.getCount() == 0) {
				try {
					cursor.close();
				} catch (Exception e) {
				}
				db.close();
				return true;
			} else {
				cursor.moveToFirst();
				boolean rtn = (cursor.getInt(0) == 0) ? false : true;
				cursor.close();
				db.close();
				return rtn;
			}
		} catch (Exception e) {
			db.close();
			return true;
		}
	}

	public void sendShortcutToDesktop() {
		sendShortcutToDesktop(null, null, null);
	}
	public void sendShortcutToDesktop(String shortcutLable, String shortcutUrl) {
		sendShortcutToDesktop(shortcutLable, null, shortcutUrl);
	}
	public void sendShortcutToDesktop(String shortcutLable, String shortcutIconPath, String shortcutUrl) {
		Intent intent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
		Bitmap bitmap = Utilities.getBitmap(shortcutIconPath);
		if (bitmap != null) {
			intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
		} else {
			intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, ShortcutIconResource.fromContext(mContext, Resource.getIconId(mContext)));
		}
		if (shortcutLable != null && !shortcutLable.trim().equals("")) {
			intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, shortcutLable);
		} else {
			intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label);
		}
		if (shortcutUrl != null && !shortcutUrl.trim().equals("")) {
			intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, Utilities.getStartMeIntent(mContext, shortcutUrl));
		} else {
			intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, Utilities.getStartMeIntent(mContext, getCurrentHome()));
		}
		intent.putExtra("duplicate", true);
		mContext.sendBroadcast(intent);
	}

}
